/**
 *
 */
package kevin.study.zephyr.domain.dao.db4o;

import java.util.HashMap;
import java.util.Map;

import kevin.study.zephyr.domain.dao.soda.ZComparator;
import kevin.study.zephyr.domain.dao.soda.ZConstraint;
import kevin.study.zephyr.domain.dao.soda.ZConstraintLink;
import kevin.study.zephyr.domain.dao.soda.ZOrder;
import kevin.study.zephyr.domain.dao.soda.ZQuery;

import com.db4o.query.Constraint;
import com.db4o.query.Query;

/**
 * 用于解析ZQuery为DB4O的Query
 *
 * @author Kevin.Huang
 * @date 2007-9-30
 */
public class ZQueryParse {

	private Map< ZConstraint, Constraint > link = new HashMap< ZConstraint, Constraint >();

	private Query rootQuery;

	/**
	 * 实际解析
	 *
	 * @return
	 */
	public Query parseZQuery(ZQuery zq, Query q) {
		this.rootQuery = q;
		// 解析Constrain
		for (Object zz : zq.getConstraint().values()) {
			recursionConstrain((ZConstraint) zz);
		}
		// 解析Order
		for (ZOrder zo : zq.getOrders()) {
			Query thisOrderQuery = genQueryByPath(this.rootQuery, zo.getField());
			if (zo.getOrder()) {
				thisOrderQuery.orderAscending();
			} else {
				thisOrderQuery.orderDescending();
			}
		}
		// 解析Comparator
		for (ZComparator zcomparator : zq.getComparators()) {
			Query thisComparatorQuery = genQueryByPath(this.rootQuery, zcomparator.getField());
			thisComparatorQuery.sortBy(zcomparator.getComparator());
		}
		return q;
	}

	/**
	 * 生成Constraint
	 *
	 * @param
	 * @param thisConstrain
	 */
	private Constraint recursionConstrain(ZConstraint zc) {
		if (!link.keySet().contains(zc)) {
			Query thisConstrainQuery = genQueryByPath(this.rootQuery, zc.getQuery().getField());
			Constraint returnConstraint = thisConstrainQuery.constrain(zc.getObject());
			// 拼接约束条件
			for (String cond : zc.getConditions()) {
				joinConstrain(returnConstraint, cond);
			}
			// 放入关联表
			link.put(zc, returnConstraint);
			// 拼接关联
			for (ZConstraintLink zLink : zc.getZConstraintLinks()) {
				if (zLink.getType().equals(ZConstraintLink.TYPE_OR)) {
					if (link.get(zLink.getZConstraint()) == null) {
						returnConstraint.or(recursionConstrain(zLink.getZConstraint()));
					} else {
						returnConstraint.or(link.get(zLink.getZConstraint()));
					}

				} else if (zLink.getType().equals(ZConstraintLink.TYPE_AND)) {
					if (link.get(zLink.getZConstraint()) == null) {
						returnConstraint.and(recursionConstrain(zLink.getZConstraint()));
					} else {
						returnConstraint.and(link.get(zLink.getZConstraint()));
					}

				}
			}

			return returnConstraint;
		} else {
			return link.get(zc);
		}
	}

	private Query genQueryByPath(Query q, String paths) {
		if (paths == null) {
			return q;
		} else {
			String[] path = paths.split("\\.");
			Query qq = q;
			for (String p : path) {
				if (p.length() != 0) {
					qq = qq.descend(p);
				}
			}
			return qq;
		}
	}

	/**
	 * 拼接Constraint
	 *
	 * @param targer
	 * @param key
	 * @return
	 */
	private Constraint joinConstrain(Constraint targer, String key) {
		if (key.equals(ZConstraint.CONTAINS)) {
			targer.contains();
		} else if (key.equals(ZConstraint.ENDSWITH_FALSE)) {
			targer.endsWith(false);
		} else if (key.equals(ZConstraint.ENDSWITH_TRUE)) {
			targer.endsWith(true);
		} else if (key.equals(ZConstraint.EQUAL)) {
			targer.equal();
		} else if (key.equals(ZConstraint.GREATER)) {
			targer.greater();
		} else if (key.equals(ZConstraint.LIKE)) {
			targer.like();
		} else if (key.equals(ZConstraint.NOT)) {
			targer.not();
		} else if (key.equals(ZConstraint.SMALLER)) {
			targer.smaller();
		} else if (key.equals(ZConstraint.STARTSWITH_FALSE)) {
			targer.startsWith(false);
		} else if (key.equals(ZConstraint.STARTSWITH_TRUE)) {
			targer.startsWith(true);
		}
		return targer;
	}
}
